package sso.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import sso.util.JwtUtils;
import sso.util.WebUtils;

import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/*构建配置安全对象*/
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    };

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //1.关闭跨域攻击
        http.csrf().disable();
        //2.配置form认证
        http.formLogin()
                //登录成功怎么处理?(向客户端返回json)
                .successHandler(successHandler()) //登录成功
                //登录失败怎么处理?(向客户端返回json)
                .failureHandler(failureHandler());//登录失败
        //假如某个资源必须认证才可访问,那没有认证怎么办?(返回json)
        http.exceptionHandling()
                .authenticationEntryPoint(authenticationEntryPoint()); //提示要认证
        //3.所有资源都要认证
        http.authorizeRequests()
                .anyRequest()//所有请求->对应任意资源
                .authenticated();//必须认证
    }

    /*登陆成功后的处理器*/
    private AuthenticationSuccessHandler successHandler(){

        return (httpServletRequest, httpServletResponse, authentication) -> {
            Map<String,Object> map = new HashMap<>();
            map.put("state", 200);
            map.put("message", "login ojbk");
            Map<String,Object> userInfo = new HashMap<>();
            //获取用户对象,此对象为登录成功以后封装了登录信息的对象
            User user = (User) authentication.getPrincipal();
            //获取用户名,并装到userInfo中
            userInfo.put("username,", user.getUsername());//登录用户
            //获取用户权限封装到userInfo中
            List<String> authorities = new ArrayList<>();
            user.getAuthorities().forEach((authority)->{
                authorities.add(authority.getAuthority());
            });
            userInfo.put("authorities", authorities);
            //创建token
            String token = JwtUtils.generatorToken(userInfo);
            map.put("token", token);
            WebUtils.writeJsonToClient(httpServletResponse,map);
        };
    }
    /*登陆失败后的处理器*/
    private AuthenticationFailureHandler failureHandler(){

        return ( httpServletRequest,httpServletResponse, exception) ->{
            Map<String,Object> map = new HashMap<>();
            map.put("state", HttpServletResponse.SC_INTERNAL_SERVER_ERROR); //500
            map.put("message", "username or password error");
            WebUtils.writeJsonToClient(httpServletResponse, map);
        };
    }
    /*没有登陆访问资源时的处理器*/
    private AuthenticationEntryPoint authenticationEntryPoint(){

        return ( httpServletRequest,  httpServletResponse,  e) -> {
            Map<String,Object> map = new HashMap<>();
            map.put("state", HttpServletResponse.SC_UNAUTHORIZED); //401
            map.put("message", "请先登陆再访问");
            WebUtils.writeJsonToClient(httpServletResponse, map);
        };
    }
    /*默认处理访问被拒绝的异常处理器对象*/
    private AccessDeniedHandler accessDeniedHandler(){

        return ( httpServletRequest,  httpServletResponse,  e) -> {
            Map<String,Object> map = new HashMap<>();
            map.put("stats", HttpServletResponse.SC_FORBIDDEN); //403
            map.put("msg", "资源访问失败");
            WebUtils.writeJsonToClient(httpServletResponse, map);
        };
    }
}
